﻿using System;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Bronze.Network;
using System.Collections.Generic;
using System.Data;

namespace Bronze.XXT.PhoneServer
{
	public class Server
	{
		public static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
		private object lockobject = new object();
		private int m_iSeqID = 1;
		private int activeTestInterval = 3 * 60;
		private int clientTimeoutSeconds = 60 * 3;
		private int clientConnectionTimeoutSeconds = 60 * 2;
		private int maxRetryCount = 2;
		private int keepConnectionAliveTime = 60 * 18;
		private KillConnectionMode killConnectionMode = KillConnectionMode.Default;
		private CommonServer svr;
		private System.Timers.Timer timer1;

		/// <summary>
		/// 关闭链接的方式
		/// </summary>
		public KillConnectionMode KillConnectionMode
		{
			get { return killConnectionMode; }
			set { killConnectionMode = value; }
		}

		/// <summary>
		/// 发送数据超时的时间（秒）
		/// </summary>
		public int SendTimeout
		{
			get { return clientTimeoutSeconds; }
			set { clientTimeoutSeconds = value; }
		}


		/// <summary>
		/// 连接初始化超时的时间（秒）
		/// </summary>
		public int ConnectionTimeout
		{
			get { return clientConnectionTimeoutSeconds; }
			set { clientConnectionTimeoutSeconds = value; }
		}


		/// <summary>
		/// 激活测试的间隔时间（秒）
		/// </summary>
		public int ActiveTestInterval
		{
			get { return activeTestInterval; }
			set { activeTestInterval = value; }
		}

		public int MaxRetryCount
		{
			get { return maxRetryCount; }
			set { maxRetryCount = value; }
		}

		/// <summary>
		/// 连接的存活期(秒)，只有当KillConnectionMode==ClientQueryConnectStatusKeepAliveTimeOut是才起作用
		/// 默认值为18*60秒
		/// </summary>
		public int KeepAliveTimeout
		{
			get { return keepConnectionAliveTime; }
			set { keepConnectionAliveTime = value; }
		}

		public event SocketHandle ClientClose;
		public event SocketHandle ClientConnect;
		public event SocketHandle ReceiveData;

		public Server(int port)
		{
			this.timer1 = new System.Timers.Timer();
			this.timer1.Interval = 10 * 1000;
			this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(timer1_Elapsed);
			this.timer1.Start();
			this.svr = new CommonServer(port);
			this.svr.OnDataIn += new OnDataInHandler(this.svr_OnDataIn);
			this.svr.OnDisconnected += new OnDisconnectedHandler(this.svr_OnDisconnected);
		}

		public void Start()
		{
			this.svr.Start();
		}

		public void Stop()
		{
			this.timer1.Stop();
			this.svr.Shutdown();
		}

		public void Send(ClientConnection connection, byte[] data)
		{
			this.svr.Send(connection.ConnectionId, data);
			connection.LastSendTime = DateTime.Now;
		}

		private void CloseConnection(ClientConnection conn, string reason)
		{
			conn.ClientStatus = ClientStatus.Offline;
			log.InfoFormat("{0}:connectionId:{1}", reason, conn.ConnectionId);
			FireClientClose(new PhoneEventArgs(conn, null, reason));
			this.svr.Disconnect(conn.ConnectionId);
		}

		private void svr_OnDataIn(object sender, SocketDataInEventArgs e)
		{
			byte[] bytes = e.Data;
			int connectionId = e.ConnectionId;
			if (bytes.Length < 10)
			{
				CloseConnection(e.Connection, "接收数据包长度小于10-强制关闭");
				log.Fatal("数据包如下:+++++++++\r\n" + Utility.BytesToString(bytes) + "\r\n\r\n");
				return;
			}
			DateTime now = DateTime.Now;
			var messages = Message.FromBytes(bytes, true);
			if (messages.Count > 0)
			{
				e.Connection.LastReciveTime = now;
				if (e.Connection.ClientStatus == ClientStatus.Unknown)
				{
					//触发新话机连接到服务器的事件
					if (this.ClientConnect != null)
					{
						this.ClientConnect(this, new PhoneEventArgs(e.Connection, messages, ""));
					}
				}

				//处理消息
				foreach (var msg in messages)
				{
					#region 话机认证请求
					if (msg.func_no == Const.PHONE_AUTHEN)
					{
						var response = new Message();
						//{
						//    seq_no = msg.seq_no,
						//    Body = new PHONE_AUTHEN_Response()
						//    {
						//
						//    }
						//};
						//TODO 需要重本地数据库里面验证该话机是否已经注册
						response.seq_no = msg.seq_no;
						var responseBody = new PHONE_AUTHEN_Response();
						responseBody.valid_flag = "0";
						string deviceID = (msg.Body as PHONE_AUTHEN_Request).DeviceId;
						//查询数据库啊话机是否已经注册
						if (!string.IsNullOrEmpty(deviceID))
						{
							try
							{
								if (BLL.Telephone.CheckPhone(deviceID.Trim()))
								{
									responseBody.valid_flag = "1";
								}
								else
								{
									responseBody.valid_flag = "0";
								}
							}
							catch (Exception ex)
							{
								log.Error("发生错误，话机注册失败", ex);

							}
						}
						response.Body = responseBody;

						var request = new Message()
						{
							seq_no = CreateSeqId(),
							Body = new ABT_STATUS_Request() { }
						};

						var sendBytes = Message.MessagesToBytes(response, request);
						e.Connection.LastSendActiveTestTime = DateTime.Now;
						Send(e.Connection, sendBytes);

						var body = msg.Body as PHONE_AUTHEN_Request;
						e.Connection.Tag = body.DeviceId;

						//检查是否有多余的无效连接，并关闭
						lock (this.lockobject)
						{
							foreach (DictionaryEntry entry in svr.ClientConnections)
							{
								var client = entry.Value as ClientConnection;
								if (client == e.Connection) continue;
								if ((body.DeviceId.Equals(client.Tag)))
								{
									log.InfoFormat("Will关闭一个空闲的连接{0},当前连接:{1},所属设备ID:{2}", client.ConnectionId, e.ConnectionId, body.DeviceId);
									client.ClientStatus = ClientStatus.Offline;
								}
							}
						}

						FireReceiveData(new PhoneEventArgs(e.Connection, msg, "话机连接"));
						break;
					}
					#endregion

					#region 网络连接查询请求
					else if (msg.func_no == Const.CONNECT_STATUS)
					{
						log.InfoFormat("#####话机向服务器发送网络状态查询请求{0}", connectionId);
						var span = DateTime.Now - e.Connection.CreateTime;
						if (span.TotalSeconds >= this.KeepAliveTimeout)
						{
							//不发送网络状态情况
							log.InfoFormat("连接的存活期超过{1}秒，迫使话机重新连接{0}", connectionId, this.KeepAliveTimeout);
							this.CloseConnection(e.Connection, "连接超过存活期");
							return;
						}
						var response = new Message()
						{
							seq_no = msg.seq_no,
							Body = new CONNECT_STATUS_Response() { }
						};
						var sendBytes = Message.MessagesToBytes(response);

						Send(e.Connection, sendBytes);
					}
					#endregion

					#region 话机向服务器回复话机状态信息
					else if (msg.func_no == Const.ABT_STATUS)
					{
						var responseBody = msg.Body as ABT_STATUS_Response;
						//TODO 把话机连接状态和版本信息写入数据库
						//话机已经连通更改状态
						string deviceID = responseBody.Device_id;
						if (!string.IsNullOrEmpty(deviceID))
						{
							try
							{
								Nullable<int> intShellStatus = null;
								Nullable<int> intPowerStatus = null;
								if (responseBody.MinitorInfo != null)
								{
									if (string.IsNullOrEmpty(responseBody.MinitorInfo.WKMStatus))
									{
										intShellStatus = Convert.ToInt32(responseBody.MinitorInfo.WKMStatus);
									}
									if (string.IsNullOrEmpty(responseBody.MinitorInfo.SDStatus))
									{
										intPowerStatus = Convert.ToInt32(responseBody.MinitorInfo.SDStatus);
									}
								}
								BLL.Telephone.SetPhoneInfo(responseBody.Device_id.Trim(),
								                           1,//连接成功
								                           intShellStatus,
								                           intPowerStatus,
								                           responseBody.VersionInfo);
							}
							catch (Exception ex)
							{
								log.Error("发生错误，话机连接状态更该失败", ex);
							}
						}
						e.Connection.ClientStatus = ClientStatus.Online;
						e.Connection.LastActiveTestResponseTime = DateTime.Now;
						e.Connection.RetryCount = 0;
						FireReceiveData(new PhoneEventArgs(e.Connection, msg, "话机状态查询"));
					}
					#endregion

					#region 刷卡签到
					else if (msg.func_no == Const.STDT_SIGN_RECS)
					{
						var response = new Message();
						//{
						//    seq_no = msg.seq_no,
						//    Body = new STDT_SIGN_RECS_Response() { valid_flag = "1" }
						//};

						response.seq_no = msg.seq_no;
						var responseBody = new STDT_SIGN_RECS_Response();

						var requestBody = msg.Body as STDT_SIGN_RECS_Request;
						int result = 0;
						string cardID = requestBody.CardID;
						if (!string.IsNullOrEmpty(cardID))
						{
							try
							{
								BLL.CheckAttendMsg attendMsg = new BLL.CheckAttendMsg();
								string strGroupName = string.Empty;

								string deviceID = requestBody.device_id;
								result = BLL.ReceiveICCard.SaveReceiveICCard(cardID.Trim(),
								                                             requestBody.start_time,
								                                             deviceID == null ? "" : deviceID.Trim(),
								                                             ref attendMsg,
								                                             ref strGroupName);
								

								object[] parameters = new object[2];
								parameters[0] = strGroupName;
								parameters[1] = attendMsg;
								Common.SignalRHelper.SendMssage(parameters);
								
							}
							catch (Exception ex)
							{
								log.Error("发生错误，刷开签到失败", ex);
							}
						}

						responseBody.valid_flag = result.ToString();
						response.Body = responseBody;

						var sendBytes = Message.MessagesToBytes(response);
						Send(e.Connection, sendBytes);

						FireReceiveData(new PhoneEventArgs(e.Connection, msg, "收到新刷卡签到信息"));
					}
					#endregion

					#region 学生卡登录
					else if (msg.func_no == Const.STDT_CARD_LOGIN)
					{
						//TODO 注意判断学生和教师卡的情况
						var body = new STDT_CARD_LOGIN_Response();
						body.Family_msisdn = new List<string>();
						body.Family_relation = new List<string>();
						body.valid_flag = "0";

						var requestBody = msg.Body as STDT_CARD_LOGIN_Request;
						string strCardID = requestBody.CardID;
						int intFamilyNumCount = 0;
						if (!string.IsNullOrEmpty(strCardID))
						{
							try
							{
								body.valid_flag = BLL.UserICCard.CheckICCard(strCardID.Trim()).ToString();
								if (body.valid_flag == "1")//当学生卡是获取亲情号码
								{
									var list = BLL.UserICCard.GetFamilyNumsByStuId(requestBody.CardID);
									string strCall = string.Empty;
									string famliyNum = string.Empty;
									list.ForEach(o =>
									             {
									             	strCall = o[0].ToString();
									             	//亲情号码
									             	for (int i = 2; i < 5; i++)
									             	{
									             		famliyNum = o[i].ToString();
									             		if (!string.IsNullOrEmpty(famliyNum))
									             		{
									             			body.Family_msisdn.Add(famliyNum);
									             			body.Family_relation.Add(strCall);
									             			intFamilyNumCount++;
									             		}
									             	}
									             });
								}
							}
							catch (Exception ex)
							{
								log.Error("发生错误，学生亲情号码失败", ex);
							}
						}
						body.Family_num = intFamilyNumCount.ToString();

						var response = new Message()
						{
							seq_no = msg.seq_no,
							Body = body
						};

						var sendBytes = Message.MessagesToBytes(response);
						Send(e.Connection, sendBytes);

						FireReceiveData(new PhoneEventArgs(e.Connection, msg, "收到学生卡登录"));
					}
					#endregion

					#region 通话记录
					if (msg.func_no == Const.CALL_BILLING)
					{
						var response = new Message();
						response.seq_no = msg.seq_no;
						var responseBody = new STDT_SIGN_RECS_Response();

						var requestBody = msg.Body as CALL_BILLING_Resquest;
						int callNum = requestBody.Call_Billing_Contents.Count;

						var callInfos = new string[callNum, 3];
						for (int i = 0; i < callNum; i++)
						{
							callInfos[i, 0] = requestBody.Call_Billing_Contents[i].start_time;
							callInfos[i, 1] = requestBody.Call_Billing_Contents[i].called_duration;
							callInfos[i, 2] = requestBody.Call_Billing_Contents[i].other_party;
						}

						try
						{
							
							responseBody.valid_flag = BLL.CallBilling.ReciveCallBilling(requestBody.card_id, requestBody.device_msisdn, callInfos);
						}
						catch(Exception ex)
						{
							responseBody.valid_flag = "1";
							log.Error("发生错误，通话记录保存失败", ex);
						}
						var sendBytes = Message.MessagesToBytes(response);
						Send(e.Connection, sendBytes);

						FireReceiveData(new PhoneEventArgs(e.Connection, msg, "收到通话清单信息"));
					}
					#endregion

					#region 未定义的消息类型

					else
					{
						log.InfoFormat("###未处理的消息func_no={0},数据如下", msg.func_no);
						log.Fatal("+++++++++++\r\n" + Utility.BytesToString(bytes) + "\r\n\r\n");
					}

					#endregion
				}
			}
			else
			{
				if (e.Connection.DirtyDataCount >= 3)
				{
					CloseConnection(e.Connection, "接收数据包异常-强制关闭");
				}
				else
				{
					e.Connection.DirtyDataCount++;
				}
				//把数据记录下来
				log.Fatal("+++++++++++\r\n" + Utility.BytesToString(bytes) + "\r\n\r\n");
			}
		}

		private void FireReceiveData(PhoneEventArgs e)
		{
			if (this.ReceiveData != null)
			{
				this.ReceiveData(this, e);
			}
		}


		private void FireClientClose(PhoneEventArgs e)
		{
			try
			{
				if (this.ClientClose != null)
				{
					this.ClientClose(this, e);
				}
				//BLL.Telephone.SetPhoneConnectStatus(2,e.)
			}
			catch (Exception ex)
			{
				log.Error("关闭连接时异常", ex);
			}
		}

		private void svr_OnDisconnected(object sender, SocketDisconnectedEventArgs e)
		{
			if (e.Connection == null)
			{
				return;
			}
			e.Connection.ClientStatus = ClientStatus.Offline;
			this.FireClientClose(new PhoneEventArgs(e.Connection));
		}

		private void timer1_Tick(object sender, EventArgs e)
		{

		}

		private void SendActiveTest(ClientConnection conn)
		{
			var request = new Message()
			{
				seq_no = CreateSeqId(),
				Body = new ABT_STATUS_Request() { }
			};

			var sendBytes = Message.MessagesToBytes(request);
			Send(conn, sendBytes);
			conn.LastSendActiveTestTime = DateTime.Now;
		}

		void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			timer1.Enabled = false;
			try
			{
				lock (this.lockobject)
				{
					foreach (DictionaryEntry entry in svr.ClientConnections)
					{
						var client = entry.Value as ClientConnection;
						TimeSpan span = (TimeSpan)(DateTime.Now - client.LastSendTime);

						if (client.ClientStatus == Network.ClientStatus.Unknown)
						{
							TimeSpan span1 = (TimeSpan)(DateTime.Now - client.CreateTime);
							if (span1.TotalSeconds >= ConnectionTimeout)
							{
								client.ClientStatus = ClientStatus.Offline;
							}
						}
						else if (client.ClientStatus == ClientStatus.Online)
						{
							TimeSpan activeSendSpan = (TimeSpan)(DateTime.Now - client.LastSendActiveTestTime);
							if (client.LastSendActiveTestTime > client.LastActiveTestResponseTime)
							{
								if (activeSendSpan.TotalSeconds > this.SendTimeout)
								{
									if (client.RetryCount < MaxRetryCount)
									{
										client.RetryCount++;
										this.SendActiveTest(client);
										log.InfoFormat("激活测试失败{0}，重试{1}次", client.ConnectionId, client.RetryCount);
										log.InfoFormat("重新发送激活测试{0}", client.ConnectionId);
									}
									else
									{
										//使用激活测试超时检测连接的状态
										if ((this.KillConnectionMode & KillConnectionMode.ActiveTestTimeOut) == KillConnectionMode.ActiveTestTimeOut)
										{
											client.ClientStatus = ClientStatus.Offline;
										}
										log.InfoFormat("激活测试失败{0}，应该关闭连接", client.ConnectionId);
									}
								}
							}
							else
							{
								if (activeSendSpan.TotalSeconds > this.ActiveTestInterval)
								{
									this.SendActiveTest(client);
									log.InfoFormat("发送激活测试{0}", client.ConnectionId);
								}
							}
						}

						if (client.ClientStatus == ClientStatus.Offline)
						{
							this.CloseConnection(client, "强制关闭");
						}
					}
				}
			}
			catch
			{
			}
			finally
			{
				timer1.Enabled = true;
			}
		}

		protected string CreateSeqId()
		{
			int id = m_iSeqID;
			Interlocked.Increment(ref m_iSeqID);
			if (m_iSeqID > 9999)
				m_iSeqID = 1;
			return id.ToString().PadLeft(4, '0');
		}
	}

	public class Connection
	{
		public int Id;
		public string Text;
		public string Device_id;
		public override string ToString()
		{
			return Text;
		}
	}

	public enum KillConnectionMode
	{
		Default = 0,

		/// <summary>
		/// 使用激活测试超时检测连接的状态
		/// </summary>
		ActiveTestTimeOut = 1,

		/// <summary>
		/// 使用发送数据超时检测连接的状态
		/// </summary>
		//TODO 尚未实现
		SendTimeOut = 2,

		/// <summary>
		/// 话机向服务器定时反向查询,判断连接的存活期
		/// </summary>
		ClientQueryConnectStatusKeepAliveTimeOut = 4
	}

	public delegate void SocketHandle(object sender, PhoneEventArgs e);
}

